home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / CHESS.PAK / WCHESS.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  26.8 KB  |  1,068 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1993 by Borland International
  3. //   examples\owl\chess\wchess.cpp
  4. //
  5. //   Owl Chess is based upon the chess program originally released
  6. //   with TURBO PASCAL GameWorks.  The chess engine was ported over
  7. //   to C, and is essentially unchanged here.  This demonstrates
  8. //   how OWL may be used to place a WINDOWS wrapper around
  9. //   DOS code, whether it is written in C or C++.
  10. //----------------------------------------------------------------------------
  11. #include <owl/pch.h>
  12. #include <owl/applicat.h>
  13. #include <owl/framewin.h>
  14. #include <owl/static.h>
  15. #include <owl/opensave.h>
  16. #include <owl/inputdia.h>
  17. #include <owl/dc.h>
  18. #include <string.h>
  19. #include <stdio.h>
  20.  
  21. #include "wcdefs.h"
  22. #include "info.h"
  23. #include "wchess.h"
  24. #include "edit.h"
  25. #include "colors.h"
  26. #include "pvalue.h"
  27. #include "externs.h"
  28.  
  29. #undef MAXPATH
  30. #define MAXPATH  160
  31.  
  32. //
  33. //  Global Variables
  34. //
  35. TColor WhiteSquareColor = TColor::White;
  36. TColor BlackSquareColor(0, 128, 0);      // green
  37.  
  38. BOOL         ShowBestLine = true;
  39. TInfoWindow* TInfo;
  40. HBRUSH       hBlackBrush;
  41. HBRUSH       hWhiteBrush;
  42. HWND         hWndMain;
  43. HBITMAP      PieceBmpArray[6][2];
  44. HBITMAP      MaskArray[6];
  45. HCURSOR      hArrowCursor;
  46. HCURSOR      hWaitCursor;
  47. HMENU        ThinkMenu;
  48. HMENU        MainMenu;
  49. HANDLE       hAccel;
  50. COLORTYPE    ComputerColor;
  51. short        LINESIZE;
  52. short        CHARSIZE;
  53. int          CAPTIONY;
  54. BOOL         Editing;
  55. int          BORDERSIZE;
  56. const        BORDERYEXTRA = 4; // 4 for spacing
  57. short        INFOXSIZE, INFOYSIZE;
  58. BOOL         SoundOn;
  59.  
  60.  
  61. // --------------- TMessageDialog ----------------------
  62.  
  63. //
  64. // This creates a BWCC style message box using a static template
  65. // from the RC file.  A more versatile version would dynamically
  66. // create the message box to fit the size of each message, and allow
  67. // the user to specify what type of buttons to display, much like
  68. // the windows version of MessageBox
  69. //
  70. class TMessageDialog : public TDialog {
  71.   public:
  72.     TMessageDialog(TWindow* parent, int resourceId, const char far* message,
  73.                    const char far* title);
  74.  
  75.   protected:
  76.     void SetupWindow();
  77.  
  78.   private:
  79.     const char far* NewMessage;
  80.     const char far* NewTitle;
  81. };
  82.  
  83. TMessageDialog::TMessageDialog(TWindow* parent, int resourceId,
  84.                                const char far* message, const char far* title)
  85. :
  86.   TDialog(parent, resourceId)
  87. {
  88.    NewMessage = message;
  89.    NewTitle = title;
  90. }
  91.  
  92. void
  93. TMessageDialog::SetupWindow()
  94. {
  95.   // failure to explicitly call the ancestor version of SetupWindow
  96.   // will result in incorrect behavior.  It should always be done
  97.   // first in any derivation of SetupWindow.
  98.   //
  99.   TDialog::SetupWindow();
  100.   SetDlgItemText(ID_INPUT, NewMessage);
  101.   SetWindowText(NewTitle);
  102. }
  103.  
  104. // --------------- TEndDialog ----------------------
  105.  
  106. class TEndDialog : public TDialog {
  107.   public:
  108.     TEndDialog(TWindow* parent, int resourceId, const char far* message);
  109.  
  110.   protected:
  111.     void SetupWindow();
  112.     void CmYes() {CloseWindow(IDYES);}
  113.     void CmNo() {CloseWindow(IDNO);}
  114.  
  115.   private:
  116.     const char far* EndMessage;
  117.  
  118.   DECLARE_RESPONSE_TABLE(TEndDialog);
  119. };
  120.  
  121. DEFINE_RESPONSE_TABLE1(TEndDialog, TDialog)
  122.   EV_COMMAND(IDYES, CmYes),
  123.   EV_COMMAND(IDNO, CmNo),
  124. END_RESPONSE_TABLE;
  125.  
  126. TEndDialog::TEndDialog(TWindow* parent, int resourceId, const char far* message)
  127. :
  128.   TDialog(parent, resourceId)
  129. {
  130.   EndMessage = message;
  131. }
  132.  
  133. void
  134. TEndDialog::SetupWindow()
  135. {
  136.   TDialog::SetupWindow();
  137.   SetDlgItemText(ID_INPUT, EndMessage);
  138. }
  139.  
  140. // --------------- TChessWindow ----------------------
  141.  
  142. class TChessWindow : public TWindow {
  143.   public:
  144.     TChessWindow();
  145.    ~TChessWindow();
  146.     void SetupWindow();
  147.     void GetWindowClass(WNDCLASS& wndClass);
  148.     char far* GetClassName() {return "ChessWindow";}
  149.  
  150.     void Paint(TDC& dc, bool erase, TRect& rect);
  151.  
  152.     void EvLButtonDown(uint, TPoint&);
  153.     void EvMouseMove(uint, TPoint&);
  154.  
  155.     void CmNewGame();
  156.     void CmRestoreGame();
  157.     void CmSaveGame();
  158.     void CmSaveGameAs();
  159.     void CmUndoMove();
  160.     void CmRedoUndo();
  161.     void CmMovePieces();
  162.     void CmMoveTime();
  163.     void CmTotalTime();
  164.     void CmDemo();
  165.     void CmInfiniteSearch();
  166.     void CmPlySearch();
  167.     void CmMateSearch();
  168.     void CmSinglePlayer();
  169.     void CmTwoPlayer();
  170.     void CmAutoPlay();
  171.     void CmReverseBoard();
  172.     void CmEasy();
  173.     void CmHint();
  174.     void CmPass();
  175.     void CmDone();
  176.     void CmClear();
  177.     void CmCancel();
  178.     void CmError();
  179.     void CmMatching();
  180.     void CmWhiteTurn();
  181.     void CmBlackTurn();
  182.     void CmColors();
  183.     void CmPieceValues();
  184.     void CmBestLine();
  185.     void CmMouseDrag();
  186.     void CmMouseSelect();
  187.     void CmSound();
  188.     void EvTimer(uint);
  189.  
  190.     void EndGame();
  191.     void DoEdit(TPoint& point);
  192.     void ComputersTurn();
  193.     void UnCheckLevelMenu(LEVELTYPE);
  194.     void NormalSetup();
  195.     void CheckLevelMenu(LEVELTYPE);
  196.     bool CanClose() {
  197.       if (ComputerThinking || AutoPlay) {
  198.         PostMessage(WM_COMMAND, CM_STOP);
  199.         PostMessage(WM_COMMAND, IDM_EXIT);
  200.         return false;
  201.       }
  202.       QuitProgram();
  203.       return true;
  204.     }
  205.  
  206.   private:
  207.     enum TURNTYPE { player, computer };
  208.     TInfoWindow*    TInfo;    // information window
  209.     TEditBarWindow* TEditBar; // edit bar
  210.     bool       NewGame;       // a new game is being set up?
  211.     char*      FileName;      // last saved game
  212.     TRect      MainWndRect;   // coordinates for the main window
  213.     TRect      InfoAreaRect;  // coordinates for the information window
  214.     HMENU      hMenu;         // handle to the main menu
  215.     HMENU      hThinkMenu;    // handle to the short (stop) menu
  216.     HMENU      hEditMenu;     // handle to the edit (arrange) menu
  217.     TURNTYPE   WhoseTurn;     // players or computers turn?
  218.     SQUARETYPE MoveStartSquare; // starting square for move
  219.     SQUARETYPE MoveEndSquare; // ending square for move
  220.     COLORTYPE  CurPlayer;     // current player
  221.     bool       GotStartSquare; // did the user select a valid piece to move?
  222.     HBRUSH     hBKBrush;      // handle to brush to paint main window backgnd
  223.     HBITMAP    hBKBrushBmp;   // small bitmap used to paint main window bkgnd
  224.     bool       Modified;      // has the board been changed in edit mode?
  225.     bool       EditingBoard;  // is the user editing the board
  226.     bool       Dragging;      // in drag mode?
  227.     BOARDTYPE* SaveBoard;     // saved board setup in case user cancels edit
  228.  
  229.   DECLARE_RESPONSE_TABLE(TChessWindow);
  230. };
  231.  
  232. // ------------- TChessWindow response table functions -----------------------
  233.  
  234. DEFINE_RESPONSE_TABLE1(TChessWindow, TWindow)
  235.   EV_WM_LBUTTONDOWN,
  236.   EV_WM_MOUSEMOVE,
  237.   EV_COMMAND(CM_FILENEW, CmNewGame),
  238.   EV_COMMAND(CM_FILEOPEN, CmRestoreGame),
  239.   EV_COMMAND(CM_FILESAVE, CmSaveGame),
  240.   EV_COMMAND(CM_FILESAVEAS, CmSaveGameAs),
  241.   EV_COMMAND(CM_UNDO, CmUndoMove),
  242.   EV_COMMAND(CM_REDO, CmRedoUndo),
  243.   EV_COMMAND(IDM_MOVEPIECE, CmMovePieces),
  244.   EV_COMMAND(IDM_MOVETIME, CmMoveTime),
  245.   EV_COMMAND(IDM_TOTALTIME, CmTotalTime),
  246.   EV_COMMAND(IDM_DEMO, CmDemo),
  247.   EV_COMMAND(IDM_INFINITE, CmInfiniteSearch),
  248.   EV_COMMAND(IDM_PLY, CmPlySearch),
  249.   EV_COMMAND(IDM_MATE, CmMateSearch),
  250.   EV_COMMAND(IDM_SINGLE, CmSinglePlayer),
  251.   EV_COMMAND(IDM_TWOPLAYER, CmTwoPlayer),
  252.   EV_COMMAND(IDM_AUTO, CmAutoPlay),
  253.   EV_COMMAND(IDM_REVERSE, CmReverseBoard),
  254.   EV_COMMAND(IDM_EASY, CmEasy),
  255.   EV_COMMAND(IDM_HINT, CmHint),
  256.   EV_COMMAND(IDM_PASS, CmPass),
  257.   EV_COMMAND(EM_DONE, CmDone),
  258.   EV_COMMAND(EM_CLEAR, CmClear),
  259.   EV_COMMAND(EM_CANCEL, CmCancel),
  260.   EV_COMMAND(EM_ERROR, CmError),
  261.   EV_COMMAND(IDM_MATCHING, CmMatching),
  262.   EV_COMMAND(IDM_WHITETURN, CmWhiteTurn),
  263.   EV_COMMAND(IDM_BLACKTURN, CmBlackTurn),
  264.   EV_COMMAND(IDM_COLORS, CmColors),
  265.   EV_COMMAND(IDM_PIECEVALUES, CmPieceValues),
  266.   EV_COMMAND(IDM_BESTLINE, CmBestLine),
  267.   EV_COMMAND(IDM_MOUSEDRAG, CmMouseDrag),
  268.   EV_COMMAND(IDM_MOUSESELECT, CmMouseSelect),
  269.   EV_COMMAND(IDM_SOUND, CmSound),
  270.  
  271.   EV_WM_TIMER,
  272. END_RESPONSE_TABLE;
  273.  
  274. // ------------- TChessWindow member functions -----------------
  275.  
  276. TChessWindow::TChessWindow()
  277. :
  278.   TWindow(0, 0, 0)
  279. {
  280.   TScreenDC dc;
  281.   TEXTMETRIC tm;
  282.   dc.GetTextMetrics(tm);
  283.   CHARSIZE = short(tm.tmAveCharWidth);
  284.   LINESIZE = short(tm.tmHeight + tm.tmExternalLeading);
  285.  
  286.   CAPTIONY = ::GetSystemMetrics(SM_CYCAPTION) + ::GetSystemMetrics(SM_CYMENU);
  287.   BORDERSIZE = LINESIZE + MYFRAMESIZE;
  288.   TInfo = new TInfoWindow(this, "InfoWindow");
  289.   TEditBar = new TEditBarWindow(this, "EditBar");
  290.   SoundOn = true;
  291.   ::TInfo = TInfo;
  292.  
  293.   Attr.Style = WS_CHILD | WS_VISIBLE;
  294.   Attr.X = 5;
  295.   Attr.Y = 5;
  296.   Attr.H = CAPTIONY + BORDERSIZE*2 + INFOYSIZE + BORDERYEXTRA +
  297.     2*GetSystemMetrics(SM_CYBORDER);
  298.  
  299.   Attr.W = BORDERSIZE*4 + MAXBDSIZE*SQUARE_SIZE + INFOXSIZE +
  300.     2*GetSystemMetrics(SM_CXBORDER) + 2*MYFRAMESIZE;
  301.  
  302.   SetBkgndColor(TColor::Sys3dFace);
  303.  
  304.   FileName = new char[MAXPATH];
  305.   WhoseTurn = player;
  306.   CurPlayer = white;
  307.   ::ComputerColor = black;
  308.   ::Editing = EditingBoard = GotStartSquare = FALSE;
  309.   NewGame = TRUE;
  310. }
  311.  
  312. TChessWindow::~TChessWindow()
  313. {
  314.   delete[] FileName;
  315.   delete TInfo;
  316.   ::DeleteObject(hWhiteBrush);
  317.   ::DeleteObject(hBlackBrush);
  318.   ::DeleteObject(hBKBrushBmp);
  319.   ::DestroyMenu(hThinkMenu);
  320.   ::DestroyMenu(hEditMenu);
  321.   for (int i = 0; i < 6; i++) {
  322.     ::DeleteObject(MaskArray[i]);
  323.     for (int j = 0; j < 2; j++)
  324.       ::DeleteObject(PieceBmpArray[i][j]);
  325.   }
  326.   KillTimer(TIMEID);
  327. }
  328.  
  329. void
  330. TChessWindow::GetWindowClass(WNDCLASS& wndClass)
  331. {
  332.   // Again, call the ancestor version first, as must also
  333.   // be done with SetupWindow and InitInstance
  334.   //
  335.   TWindow::GetWindowClass(wndClass);
  336.  
  337.   // this allows you to specify your own values for the
  338.   // window class, which OWL will register for you
  339.   //
  340.   ::hArrowCursor = wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);
  341.   hBKBrushBmp = GetApplication()->LoadBitmap("BKBrush");
  342.   hBKBrush = ::CreatePatternBrush(hBKBrushBmp);
  343.  
  344.   wndClass.hbrBackground = hBKBrush;
  345.   wndClass.lpszMenuName = 0;
  346.   wndClass.hIcon = LoadIcon(*GetApplication(), "ChessIcon");
  347. }
  348.  
  349. void
  350. TChessWindow::SetupWindow()
  351. {
  352.   TWindow::SetupWindow();
  353.  
  354.   ::hWndMain = GetHandle();
  355.   ::hWaitCursor = ::LoadCursor(0, IDC_WAIT);
  356.  
  357.   ::PieceBmpArray[pawn-1][white] = GetApplication()->LoadBitmap("WPawn");
  358.   ::PieceBmpArray[pawn-1][black] = GetApplication()->LoadBitmap("BPawn");
  359.   ::PieceBmpArray[rook-1][white] = GetApplication()->LoadBitmap("WRook");
  360.   ::PieceBmpArray[rook-1][black] = GetApplication()->LoadBitmap("BRook");
  361.   ::PieceBmpArray[knight-1][black] = GetApplication()->LoadBitmap("BKnight");
  362.   ::PieceBmpArray[bishop-1][black] = GetApplication()->LoadBitmap("BBishop");
  363.   ::PieceBmpArray[queen-1][black] = GetApplication()->LoadBitmap("BQueen");
  364.  
  365.   ::PieceBmpArray[knight-1][white] = GetApplication()->LoadBitmap("WKnight");
  366.   ::PieceBmpArray[bishop-1][white] = GetApplication()->LoadBitmap("WBishop");
  367.   ::PieceBmpArray[queen-1][white] = GetApplication()->LoadBitmap("WQueen");
  368.  
  369.   ::PieceBmpArray[king-1][white] =  GetApplication()->LoadBitmap("WKing");
  370.   ::PieceBmpArray[king-1][black] =  GetApplication()->LoadBitmap("BKing");
  371.  
  372.   ::MaskArray[pawn-1] =   GetApplication()->LoadBitmap("PMask");
  373.   ::MaskArray[rook-1] =   GetApplication()->LoadBitmap("RMask");
  374.   ::MaskArray[knight-1] = GetApplication()->LoadBitmap("KTMask");
  375.   ::MaskArray[bishop-1] = GetApplication()->LoadBitmap("BMask");
  376.   ::MaskArray[queen-1] =  GetApplication()->LoadBitmap("QMask");
  377.   ::MaskArray[king-1] =   GetApplication()->LoadBitmap("KMask");
  378.  
  379.   InfoAreaRect = MainWndRect = GetClientRect();
  380.   InfoAreaRect.left = MainWndRect.right -= BORDERSIZE*2 + INFOXSIZE;
  381.  
  382.   MainMenu = hMenu = GetApplication()->LoadMenu("TChessMenu");
  383.   ::ThinkMenu = hThinkMenu = GetApplication()->LoadMenu("TChessThinkMenu");
  384.   hEditMenu = GetApplication()->LoadMenu("TChessEditMenu");
  385.   GetParentO()->SetMenu(hMenu);
  386.  
  387.   ::Talk();
  388.   CheckLevelMenu(Level);
  389.   ::hWhiteBrush = ::CreateSolidBrush(WhiteSquareColor);
  390.   ::hBlackBrush = ::CreateSolidBrush(BlackSquareColor);
  391.  
  392.   Dragging = true;
  393. }
  394.  
  395. void
  396. TChessWindow::Paint(TDC& dc, bool, TRect&)
  397. {
  398.   DrawFrame(dc, MainWndRect);
  399.   DrawFrame(dc, InfoAreaRect);
  400.   PrintBoard();
  401. }
  402.  
  403. void
  404. TChessWindow::EvLButtonDown(uint, TPoint& point)
  405. {
  406.   if (EditingBoard) {
  407.     DoEdit(point);
  408.     return;
  409.   }
  410.  
  411.   if (WhoseTurn == computer && !NoComputerMove)
  412.     return;
  413.  
  414.   if (!GotStartSquare) {
  415.     MoveStartSquare = GetValidSquare(point, CurPlayer, true);
  416.     if (MoveStartSquare == -1)
  417.       return;
  418.     GotStartSquare = true;
  419.     if (!Dragging)
  420.       DrawInvertedBitmap(MoveStartSquare);
  421.     else
  422.       DragStart(MoveStartSquare, point);
  423.  
  424.   }
  425.   else {
  426.     MoveEndSquare = GetValidSquare(point, CurPlayer, false);
  427.     GotStartSquare = false;
  428.     if (MoveEndSquare == -1) {
  429.       if (Dragging)
  430.         DragEnd(FALSE);
  431.       Warning("Invalid Move");
  432.       DrawNormalBitmap(MoveStartSquare);
  433.       return;
  434.     }
  435.     if (!MoveCheck(MoveStartSquare, MoveEndSquare)) {
  436.       if (Dragging)
  437.         DragEnd(FALSE);
  438.       DrawNormalBitmap(MoveStartSquare);
  439.       return;
  440.     }
  441.  
  442.     ::GotValidMove = true;
  443.     ::EnableMenuItem(hMenu, CM_UNDO, MF_BYCOMMAND | MF_ENABLED);
  444.     if (GameOver)
  445.       EndGame();
  446.     else if (NoComputerMove == false)
  447.       ComputersTurn();
  448.     else if (::MultiMove)
  449.       CurPlayer = (CurPlayer == white) ? black : white;
  450.   }
  451. }
  452.  
  453. void
  454. TChessWindow::ComputersTurn()
  455. {
  456.   WhoseTurn = computer;
  457.   SetClassWindowCursor(GetHandle(), ::hWaitCursor);
  458.   GetParentO()->SetMenu(hThinkMenu);
  459.   ProgramMove();
  460.   GetParentO()->SetMenu(hMenu);
  461.  
  462.   WhoseTurn = player;
  463.   SetClassWindowCursor(GetHandle(), hArrowCursor);
  464.   if (GameOver)
  465.     EndGame();
  466. }
  467.  
  468. void
  469. TChessWindow::CmNewGame()
  470. {
  471.   KillTimer(TIMEID);
  472.   TInfo->SetTimerText("");
  473.   ::EnableMenuItem(hMenu, CM_UNDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  474.   ::EnableMenuItem(hMenu, CM_REDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  475.   NewGame = TRUE;
  476.   ::NewGame();
  477.   ::PrintBoard();
  478.   CurPlayer = Player;
  479.   ComputerColor = Opponent;
  480. }
  481.  
  482. void
  483. TChessWindow::CmRestoreGame()
  484. {
  485.   TOpenSaveDialog::TData data (
  486.     OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_NOREADONLYRETURN,
  487.     "Chess Game Files (*.CHS)\0*.chs\0",
  488.     0,
  489.     0,
  490.     "CHS"
  491.   );
  492.  
  493.   if (TFileOpenDialog(this, data).Execute() == IDOK) {
  494.     NewGame = FALSE;
  495.     strcpy(FileName, data.FileName);
  496.     ::RestoreGame(FileName);
  497.     CurPlayer = Player;
  498.     ComputerColor = Opponent;
  499.     ::EnableMenuItem(hMenu, CM_REDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  500.     ::EnableMenuItem(hMenu, CM_UNDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  501.   }
  502. }
  503.  
  504. void
  505. TChessWindow::CmSaveGameAs()
  506. {
  507.   TOpenSaveDialog::TData data (
  508.     OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
  509.     "Chess Game Files (*.CHS)|*.chs|",
  510.     0,
  511.     0,
  512.     "CHS"
  513.   );
  514.   if (TFileSaveDialog(this, data).Execute() == IDOK) {
  515.     NewGame = FALSE;
  516.     strcpy(FileName, data.FileName);
  517.     ::SaveGame(FileName);
  518.   }
  519. }
  520.  
  521. void
  522. TChessWindow::CmSaveGame()
  523. {
  524.   if (NewGame)
  525.     CmSaveGameAs();
  526.   else
  527.     ::SaveGame(FileName);
  528. }
  529.  
  530. void
  531. TChessWindow::CmError()
  532. {
  533.   TMessageDialog(this, DR_CHESSERROR, buf, "OWL Chess Error").Execute();
  534. }
  535.  
  536. void
  537. TChessWindow::DoEdit(TPoint& point)
  538. {
  539.   Modified = TRUE;
  540.  
  541.   SQUARETYPE square = GetValidSquare(point, black, FALSE);
  542.   if (Board[square].piece != empty) {
  543.     Board[square].piece = empty;
  544.     ::UpdateBoard();
  545.     return;
  546.   }
  547.   int selectedItem = TEditBar->GetSelectedItem();
  548.  
  549.   Board[square].piece = (PIECETYPE)(selectedItem % 6 + 1);
  550.   Board[square].color = (selectedItem < 6) ? white : black;
  551.   ::UpdateBoard();
  552. }
  553.  
  554. void
  555. TChessWindow::CmMovePieces()
  556. {
  557.   SaveBoard = new BOARDTYPE[0x78];
  558.   if (!SaveBoard) {
  559.     Error("Not enough memory");
  560.     return;
  561.   }
  562.   memcpy(SaveBoard, Board, sizeof(BOARDTYPE) * 0x78);
  563.   Editing = EditingBoard = TRUE;
  564.   TInfo->Show(SW_HIDE);
  565.   GetParentO()->SetMenu(hEditMenu);
  566.   Modified = FALSE;
  567.   if (CurPlayer == white) {
  568.     CheckMenuItem(hEditMenu, IDM_BLACKTURN, MF_UNCHECKED);
  569.     CheckMenuItem(hEditMenu, IDM_WHITETURN, MF_CHECKED);
  570.   } else {
  571.     CheckMenuItem(hEditMenu, IDM_BLACKTURN, MF_CHECKED);
  572.     CheckMenuItem(hEditMenu, IDM_WHITETURN, MF_UNCHECKED);
  573.   }
  574.   TEditBar->Show(SW_NORMAL);
  575. }
  576.  
  577. void
  578. TChessWindow::CmDone()
  579. {
  580.   SQUARETYPE sq;
  581.   int        kingCount[2] = { 0, 0 };
  582.   int        totalCount[2] = { 0, 0 };
  583.   bool       done = false;
  584.  
  585.   if (Modified) {
  586.     for (sq = 0; sq < 0x78; sq++)
  587.       if (!(sq & 0x88)) {
  588.         if (Board[sq].piece != empty) {
  589.           totalCount[Board[sq].color]++;
  590.           if (Board[sq].piece == king)
  591.             kingCount[Board[sq].color]++;
  592.         }
  593.       }
  594.     if (totalCount[white] <= 16 && kingCount[white] == 1 &&
  595.         totalCount[black] <= 16 && kingCount[black] == 1) {
  596.       ResetNewPos();
  597.       if (!Attacks(Player, PieceTab[Opponent][0].isquare))
  598.         done = TRUE;
  599.       else
  600.         Error("Illegal King position");
  601.     } else
  602.        Error("Wrong number of pieces");
  603.   } else
  604.     NormalSetup();
  605.  
  606.   if (done)
  607.     NormalSetup();
  608. }
  609.  
  610. void
  611. TChessWindow::CmClear()
  612. {
  613.   Modified = TRUE;
  614.   for (SQUARETYPE sq = 0; sq <= 0x77; sq++)
  615.     Board[sq].piece = empty;
  616.   ::UpdateBoard();
  617. }
  618.  
  619. void
  620. TChessWindow::CmCancel()
  621. {
  622.   memcpy(Board, SaveBoard, sizeof(BOARDTYPE) * 0x78);
  623.   ResetNewPos();
  624.   NormalSetup();
  625. }
  626.  
  627. void
  628. TChessWindow::NormalSetup()
  629. {
  630.   TEditBar->Show(SW_HIDE);
  631.   TInfo->Show(SW_NORMAL);
  632.   GetParentO()->SetMenu(hMenu);
  633.   delete [] SaveBoard;
  634.   Editing = EditingBoard = FALSE;
  635.   ::UpdateBoard();
  636. }
  637.  
  638. void
  639. TChessWindow::CmMoveTime()
  640. {
  641.   char* secsPerMove = new char[40];
  642.   sprintf(secsPerMove, "%.2lf", ::AverageTime);
  643.  
  644.   if (TInputDialog(this, "Set Seconds per Move",
  645.       "Seconds Per Move:", secsPerMove, 19).Execute() == IDOK) {
  646.     double newMoveTime = atof(secsPerMove);
  647.     if (newMoveTime > 0.0) {
  648.       if (::Level != normal) {
  649.         UnCheckLevelMenu(Level);
  650.         ::CheckMenuItem(hMenu, IDM_MOVETIME, MF_CHECKED);
  651.       }
  652.       ::Level = normal;
  653.       ::AverageTime = newMoveTime;
  654.       PrintCurLevel();
  655.       for (COLORTYPE color = white; color <= black; ((int)color)++)
  656.         ::ChessTime[color].totaltime = (::MoveNo / 2) * ::AverageTime;
  657.       ::MaxLevel = MAXPLY;
  658.  
  659.     } else
  660.       Error("Invalid time.  No change made.");
  661.   }
  662.   delete secsPerMove;
  663. }
  664.  
  665. void
  666. TChessWindow::CmTotalTime()
  667. {
  668.   char* totalMoveTime = new char[40];
  669.   sprintf(totalMoveTime, "%.2lf", ::AverageTime);
  670.  
  671.   if (TInputDialog(this, "Set Minutes per Game", "Minutes Per Game:",
  672.       totalMoveTime, 19).Execute() == IDOK) {
  673.     double newMoveTime = atof(totalMoveTime);
  674.     if (newMoveTime > 0.0) {
  675.       if (::Level != fullgametime) {
  676.         UnCheckLevelMenu(Level);
  677.         ::CheckMenuItem(hMenu, IDM_TOTALTIME, MF_CHECKED);
  678.       }
  679.       ::Level = fullgametime;
  680.       ::AverageTime = newMoveTime;
  681.       ::PrintCurLevel();
  682.       for (COLORTYPE color = white; color <= black; ((int)color)++)
  683.         ::ChessTime[color].totaltime = (::MoveNo / 2) * ::AverageTime;
  684.       ::MaxLevel = MAXPLY;
  685.  
  686.     } else
  687.       Error("Invalid time.  No change made.");
  688.   }
  689.   delete totalMoveTime;
  690. }
  691.  
  692. void
  693. TChessWindow::CmDemo()
  694. {
  695.   bool isEasy = false;
  696.   if (::Level == easygame) {
  697.     isEasy = true;
  698.     ::Level = normal;
  699.     HideAttacks();
  700.   }
  701.   AutoPlay = true;
  702.   ComputersTurn();
  703.   if (isEasy) {
  704.     ::Level = easygame;
  705.     ::UpdateBoard();
  706.   }
  707.   CurPlayer = Player;
  708.   ComputerColor = Opponent;
  709.   ::PrintCurLevel();
  710. }
  711.  
  712. void
  713. TChessWindow::CmMatching()
  714. {
  715.   if (::Level != matching) {
  716.     UnCheckLevelMenu(Level);
  717.     ::CheckMenuItem(hMenu, IDM_MATCHING, MF_CHECKED);
  718.   }
  719.   ::Level = matching;
  720.   ::PrintCurLevel();
  721. }
  722.  
  723. void
  724. TChessWindow::CmInfiniteSearch()
  725. {
  726.   if (::Level != infinite) {
  727.     UnCheckLevelMenu(Level);
  728.     ::CheckMenuItem(hMenu, IDM_INFINITE, MF_CHECKED);
  729.   }
  730.   ::Level = infinite;
  731.   ::MaxLevel = MAXPLY;
  732.   ::PrintCurLevel();
  733. }
  734.  
  735. void
  736. TChessWindow::CmPlySearch()
  737. {
  738.   char* plySearchDepth = new char[40];
  739.   sprintf(plySearchDepth, "%d", ::MaxLevel);
  740.  
  741.   if (TInputDialog(this, "Set ply depth", "Number of plys:",
  742.       plySearchDepth, 19).Execute() == IDOK) {
  743.     int newPlyDepth = atoi(plySearchDepth);
  744.     if (newPlyDepth > 0) {
  745.       if (::Level != plysearch) {
  746.         UnCheckLevelMenu(Level);
  747.         ::CheckMenuItem(hMenu, IDM_PLY, MF_CHECKED);
  748.       }
  749.       ::MaxLevel = (BYTE)((newPlyDepth > MAXPLY) ? MAXPLY : newPlyDepth);
  750.       ::Level = plysearch;
  751.       ::PrintCurLevel();
  752.     } else
  753.       ::Error("Invalid time.  No change made.");
  754.   }
  755.   delete plySearchDepth;
  756. }
  757.  
  758. void
  759. TChessWindow::CmMateSearch()
  760. {
  761.   if (::Level != matesearch) {
  762.     UnCheckLevelMenu(Level);
  763.     ::CheckMenuItem(hMenu, IDM_MATE, MF_CHECKED);
  764.   }
  765.   ::Level = matesearch;
  766.   ::PrintCurLevel();
  767.   ComputersTurn();
  768. }
  769.  
  770. void
  771. TChessWindow::CmSinglePlayer()
  772. {
  773. }
  774.  
  775. void TChessWindow::CmTwoPlayer()
  776. {
  777.   static LEVELTYPE OldLevel = normal;
  778.   ::MultiMove = !::MultiMove;
  779.  
  780.   if (::MultiMove) {
  781.     OldLevel = ::Level;
  782.     ::ModifyMenu(hMenu, IDM_TWOPLAYER, MF_BYCOMMAND | MF_STRING,
  783.       IDM_TWOPLAYER, "&Single Player");
  784.     ::EnableMenuItem(hMenu, 2, MF_GRAYED | MF_BYPOSITION);
  785.     GetParentO()->DrawMenuBar();
  786.     ::Level = normal;
  787.     ::PrintCurLevel();
  788.  
  789.   } else {
  790.     ::ModifyMenu(hMenu, IDM_TWOPLAYER, MF_BYCOMMAND | MF_STRING,
  791.       IDM_TWOPLAYER, "&Two Player");
  792.     ::EnableMenuItem(hMenu, 2, MF_ENABLED | MF_BYPOSITION);
  793.     GetParentO()->DrawMenuBar();
  794.     ::Level = OldLevel;
  795.     ::PrintCurLevel();
  796.   }
  797. }
  798.  
  799. void TChessWindow::CmAutoPlay()
  800. {
  801. }
  802.  
  803. void
  804. TChessWindow::CmReverseBoard()
  805. {
  806.   ::Turned = !::Turned;
  807.   ::PrintBoard();
  808. }
  809.  
  810. void
  811. TChessWindow::CmUndoMove()
  812. {
  813.   if (ComputerThinking) {
  814.     MessageToPost = CM_UNDO;
  815.     return;
  816.   }
  817.   if (!Undo())
  818.     ::EnableMenuItem(hMenu, CM_UNDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  819.   ::EnableMenuItem(hMenu, CM_REDO, MF_BYCOMMAND | MF_ENABLED);
  820.   CurPlayer = Player;
  821.   ComputerColor = Opponent;
  822. }
  823.  
  824. void
  825. TChessWindow::CmRedoUndo()
  826. {
  827.   if (ComputerThinking) {
  828.     MessageToPost = CM_REDO;
  829.     return;
  830.   }
  831.   if (!Redo())
  832.     ::EnableMenuItem(hMenu, CM_REDO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  833.   ::EnableMenuItem(hMenu, CM_UNDO, MF_BYCOMMAND | MF_ENABLED);
  834.   CurPlayer = Player;
  835.   ComputerColor = Opponent;
  836. }
  837.  
  838. void
  839. TChessWindow::UnCheckLevelMenu(LEVELTYPE level)
  840. {
  841.   WORD checkItem = IDM_EASY;
  842.   switch (level) {
  843.     case normal:
  844.       checkItem = IDM_MOVETIME;
  845.       break;
  846.     case fullgametime:
  847.       checkItem = IDM_TOTALTIME;
  848.       break;
  849.     case plysearch:
  850.       checkItem = IDM_PLY;
  851.       break;
  852.     case easygame:
  853.       checkItem = IDM_EASY;
  854.       break;
  855.     case infinite:
  856.       checkItem = IDM_INFINITE;
  857.       break;
  858.     case matesearch:
  859.       checkItem = IDM_MATE;
  860.       break;
  861.     case matching:
  862.       checkItem = IDM_MATCHING;
  863.       break;
  864.   }
  865.   ::CheckMenuItem(hMenu, checkItem, MF_UNCHECKED);
  866. }
  867.  
  868. void
  869. TChessWindow::CheckLevelMenu(LEVELTYPE level)
  870. {
  871.   WORD checkItem = IDM_EASY;
  872.   switch (level) {
  873.     case normal:
  874.       checkItem = IDM_MOVETIME;
  875.       break;
  876.     case fullgametime:
  877.       checkItem = IDM_TOTALTIME;
  878.       break;
  879.     case plysearch:
  880.       checkItem = IDM_PLY;
  881.       break;
  882.     case easygame:
  883.       checkItem = IDM_EASY;
  884.       break;
  885.     case infinite:
  886.       checkItem = IDM_INFINITE;
  887.       break;
  888.     case matesearch:
  889.       checkItem = IDM_MATE;
  890.       break;
  891.     case matching:
  892.       checkItem = IDM_MATCHING;
  893.       break;
  894.   }
  895.   ::CheckMenuItem(hMenu, checkItem, MF_CHECKED);
  896. }
  897.  
  898. void
  899. TChessWindow::CmEasy()
  900. {
  901.   if (::Level != easygame) {
  902.     UnCheckLevelMenu(Level);
  903.     ::CheckMenuItem(hMenu, IDM_EASY, MF_CHECKED);
  904.   }
  905.   ::Level = easygame;
  906.   ::AverageTime = 5.;
  907.   ::MaxLevel = MAXPLY;
  908.   ::PrintCurLevel();
  909. }
  910.  
  911. void
  912. TChessWindow::EndGame()
  913. {
  914.   if (TEndDialog(this, DR_ENDGAMEDLG, EndGameMessage).Execute() != IDYES) {
  915.     PostMessage(WM_COMMAND, CM_EXIT);
  916.     return;
  917.   }
  918.   GameOver = false;
  919.   PostMessage(WM_COMMAND, CM_FILENEW);
  920. }
  921.  
  922. void
  923. TChessWindow::CmHint()
  924. {
  925.   FindHintMove();
  926.   ShowHint();
  927. }
  928.  
  929. void
  930. TChessWindow::CmPass()
  931. {
  932.   if (::Level == easygame)
  933.     HideAttacks();
  934.   CurPlayer = Opponent;
  935.   ComputerColor = Player;
  936.   ComputersTurn();
  937. }
  938.  
  939. void
  940. TChessWindow::CmWhiteTurn()
  941. {
  942.   CheckMenuItem(hEditMenu, IDM_BLACKTURN, MF_UNCHECKED);
  943.   CheckMenuItem(hEditMenu, IDM_WHITETURN, MF_CHECKED);
  944.   CurPlayer = white;
  945.   ComputerColor = black;
  946.   if (CurPlayer != Player) {
  947.     Opponent = ComputerColor;
  948.     Player = ProgramColor = CurPlayer;
  949.   }
  950. }
  951.  
  952. void
  953. TChessWindow::CmBlackTurn()
  954. {
  955.   CheckMenuItem(hEditMenu, IDM_BLACKTURN, MF_CHECKED);
  956.   CheckMenuItem(hEditMenu, IDM_WHITETURN, MF_UNCHECKED);
  957.   CurPlayer = black;
  958.   ComputerColor = white;
  959.   if (CurPlayer != Player) {
  960.     Opponent = ComputerColor;
  961.     Player = ProgramColor = CurPlayer;
  962.   }
  963. }
  964.  
  965. void
  966. TChessWindow::CmColors()
  967. {
  968.   TColorsDialog(this, "ColorsDialog").Execute();
  969.   DeleteObject(hWhiteBrush);
  970.   DeleteObject(hBlackBrush);
  971.   ::hWhiteBrush = CreateSolidBrush(WhiteSquareColor);
  972.   ::hBlackBrush = CreateSolidBrush(BlackSquareColor);
  973. }
  974.  
  975. void
  976. TChessWindow::CmPieceValues()
  977. {
  978.   TPieceValueDialog(this, "PieceValueDlg").Execute();
  979. }
  980.  
  981. void
  982. TChessWindow::CmBestLine()
  983. {
  984.   ShowBestLine = !ShowBestLine;
  985.  
  986.   if (ShowBestLine)
  987.     ::CheckMenuItem(hMenu, IDM_BESTLINE, MF_CHECKED);
  988.   else {
  989.     ::CheckMenuItem(hMenu, IDM_BESTLINE, MF_UNCHECKED);
  990.     TInfo->SetBestLineText("");
  991.   }
  992. }
  993.  
  994. void
  995. TChessWindow::CmMouseDrag()
  996. {
  997.   TPoint point;
  998.  
  999.   if (!Dragging && GotStartSquare) {
  1000.     DrawNormalBitmap(MoveStartSquare);
  1001.     GetCursorPos(point);
  1002.     DragStart(MoveStartSquare, point);
  1003.   }
  1004.   Dragging = true;
  1005.   ::CheckMenuItem(hMenu, IDM_MOUSEDRAG, MF_CHECKED);
  1006.   ::CheckMenuItem(hMenu, IDM_MOUSESELECT, MF_UNCHECKED);
  1007. }
  1008.  
  1009. void
  1010. TChessWindow::CmMouseSelect()
  1011. {
  1012.   DragEnd(true);
  1013.   Dragging = false;
  1014.   ::CheckMenuItem(hMenu, IDM_MOUSEDRAG, MF_UNCHECKED);
  1015.   ::CheckMenuItem(hMenu, IDM_MOUSESELECT, MF_CHECKED);
  1016.   if (GotStartSquare)
  1017.     DrawInvertedBitmap(MoveStartSquare);
  1018. }
  1019.  
  1020. void
  1021. TChessWindow::CmSound()
  1022. {
  1023.   SoundOn = !SoundOn;
  1024.   if (SoundOn)
  1025.     ::CheckMenuItem(hMenu, IDM_SOUND, MF_CHECKED);
  1026.   else
  1027.     ::CheckMenuItem(hMenu, IDM_SOUND, MF_UNCHECKED);
  1028. }
  1029.  
  1030. void
  1031. TChessWindow::EvMouseMove(uint, TPoint& point)
  1032. {
  1033.   if (!GotStartSquare || !Dragging)
  1034.     return;
  1035.   Drag(point);
  1036. }
  1037.  
  1038. void
  1039. TChessWindow::EvTimer(uint)
  1040. {
  1041.   DisplayTime();
  1042. }
  1043.  
  1044.  
  1045. // --------------- TChess ----------------------
  1046.  
  1047. class TChessApp : public TApplication {
  1048.   public:
  1049.    TChessApp() : TApplication() {}
  1050.    void InitMainWindow();
  1051. };
  1052.  
  1053. void
  1054. TChessApp::InitMainWindow()
  1055. {
  1056.   TFrameWindow* frame = new TFrameWindow(0, "OWL Chess", new TChessWindow, true);
  1057.   frame->Attr.AccelTable = "ChessCommands";
  1058.   frame->Attr.Style &= ~WS_THICKFRAME;
  1059.  
  1060.   SetMainWindow(frame);
  1061.   EnableCtl3d();
  1062. }
  1063.  
  1064. int OwlMain(int,char**)
  1065. {
  1066.   return TChessApp().Run();
  1067. }
  1068.